import { hilog } from "@kit.PerformanceAnalysisKit"

interface Params {
  domain: number
  tag: string
  showLog: boolean
  maxLineSize: number
}

type Args = string | number | boolean | undefined | null | object

const DOMAIN = 0
const TAG = '星铁百科'
const SHOW_LOG = true
const FORMAT = '%{public}s'
const MAX_LINE_SIZE = 1024

const defaultParams: Params = {
  domain: DOMAIN,
  tag: TAG,
  showLog: SHOW_LOG,
  maxLineSize: MAX_LINE_SIZE,
}

export class LogUtil {
  private static domain: number = DOMAIN
  private static tag: string = TAG
  private static format: string = FORMAT
  private static showLog: boolean = SHOW_LOG
  private static maxLineSize: number = MAX_LINE_SIZE

  static init(params?: Params) {
    LogUtil.domain = params?.domain ?? defaultParams.domain
    LogUtil.tag = params?.tag ?? defaultParams.tag
    LogUtil.showLog = params?.showLog ?? defaultParams.showLog
    LogUtil.maxLineSize = params?.maxLineSize ?? defaultParams.maxLineSize
  }

  static setDomain(domain: number = DOMAIN) {
    LogUtil.domain = domain
  }

  static setTag(tag: string = TAG) {
    LogUtil.tag = tag
  }

  static setShowLog(showLog: boolean = SHOW_LOG) {
    LogUtil.showLog = showLog
  }

  static setMaxLineSize(maxLineSize: number = MAX_LINE_SIZE) {
    LogUtil.maxLineSize = maxLineSize
  }

  static debug(...args: Args[]): void {
    LogUtil.debugTag("DEFAULT", ...args)
  }

  static debugTag(tag: string, ...args: Args[]): void {
    if (!LogUtil.showLog) {
      return
    }
    LogUtil.getMessages(args, (message: string) => {
      hilog.debug(LogUtil.domain, `${LogUtil.tag}/DEBUG/${tag}`, LogUtil.format, message)
    })
  }

  static info(...args: Args[]): void {
    LogUtil.infoTag("DEFAULT", ...args)
  }

  static infoTag(tag: string, ...args: Args[]): void {
    if (!LogUtil.showLog) {
      return
    }
    LogUtil.getMessages(args, (message: string) => {
      hilog.info(LogUtil.domain, `${LogUtil.tag}/INFO/${tag}`, LogUtil.format, message)
    })
  }

  static warn(...args: Args[]): void {
    LogUtil.warnTag("DEFAULT", ...args)
  }

  static warnTag(tag: string, ...args: Args[]): void {
    if (!LogUtil.showLog) {
      return
    }
    LogUtil.getMessages(args, (message: string) => {
      hilog.warn(LogUtil.domain, `${LogUtil.tag}/WARN/${tag}`, LogUtil.format, message)
    })
  }

  static error(...args: Args[]): void {
    LogUtil.errorTag("DEFAULT", ...args)
  }

  static errorTag(tag: string, ...args: Args[]): void {
    if (!LogUtil.showLog) {
      return
    }
    LogUtil.getMessages(args, (message: string) => {
      hilog.error(LogUtil.domain, `${LogUtil.tag}/ERROR/${tag}`, LogUtil.format, message)
    })
  }

  static fatal(...args: Args[]): void {
    LogUtil.fatalTag("DEFAULT", ...args)
  }

  static fatalTag(tag: string, ...args: Args[]): void {
    if (!LogUtil.showLog) {
      return
    }
    LogUtil.getMessages(args, (message: string) => {
      hilog.fatal(LogUtil.domain, `${LogUtil.tag}/FATAL/${tag}`, LogUtil.format, message)
    })
  }

  private static getMessages(args: Args[], callback: (message: string) => void): void {
    const messages: string[] = [];
    const firstMessage =
      `┌───────${LogUtil.tag}──────────────────────────────────────────────────────────────────────────`
    const firstMessageLength = firstMessage.length
    messages.push(firstMessage)
    // 获取堆栈
    const stack = new Error().stack;
    if (stack) {
      const stackArr = stack.split('\n')
      for (let i = 0; i < stackArr.length; i++) {
        const item = stackArr[i]
        if (!item.includes(LogUtil.name)) {
          messages.push(`| ${item}`)
          break
        }
      }
      // 与第一行保持一样的长度
      messages.push(`|${'─'.repeat(firstMessageLength - 1)}`)
    }
    args.map(item => {
      let message = ""
      switch (typeof item) {
        case 'object':
          message = JSON.stringify(item, null, 2)
          break
        default:
          message = String(item)
          break
      }
      if (message.length > LogUtil.maxLineSize) {
        // 切割长字符串
        const arr = message.match(new RegExp(`.{1,${LogUtil.maxLineSize}}`, 'g'))
        if (arr) {
          arr.map((item) => {
            messages.push(`| ${item}`)
          })
        } else {
          messages.push(`| ${item}`)
        }
      } else {
        // 先按 \n 切割
        const arr = message.split('\n')
        arr.map((item) => {
          messages.push(`| ${item}`)
        })
      }
    })
    messages.push(`└${'─'.repeat(firstMessageLength - 1)}`)
    messages.map(item => {
      callback(item)
    })
  }
}
